#pragma once
#include "sentencia.h"
#include "expr.h"
class Llamar :
	public Sentencia
{
public:

	Llamar(Sentencia *next,vector<Expr*> expr,string lexema):Sentencia(next)
	{
		this->expr = expr;
		this->lexema = lexema;
	}

	~Llamar(void)
	{
	}
	virtual string is(){
		return "LLAMAR";
	}

	void setExpr(vector<Expr*>expr){
		this->expr=expr;
	}

	vector<Expr*> getExpr(){
		return this->expr;
	}

	void setLexema(string lexema){
		this->lexema = lexema;
	}

	string getLexema(){
		return this->lexema;
	}

	virtual tipo_ts * validarSemantica(tabla_simbolos *tabla_de_tipo,tabla_simbolos *tabla_de_varaible){
		item_ts *its = tabla_de_varaible->get(this->lexema.append("&FP&"));
	if(its!=0){
		if(its->getTipo()->is().compare("PROCEDIMIENTO")==0 || its->getTipo()->is().compare("FUNCION")==0){
			
			if(its->getTipo()->is().compare("PROCEDIMIENTO")==0 ){
			procedimiento *pro = (procedimiento*)its->getTipo();
			if(pro->getParams()->getTable().size()==this->expr.size()){
				for(int i = 0; i<this->expr.size();i++){
					tipo_ts *tts_ = this->expr.at(i)->validarSemantica(tabla_de_tipo,tabla_de_varaible);
					if(pro->getParams()->getTable().at(i)->getTipo()->is().compare(tts_->is())!=0){
						if((pro->getParams()->getTable().at(i)->getTipo()->is().compare("REAL")==0 || pro->getParams()->getTable().at(i)->getTipo()->is().compare("ENTERO")==0)&&(tts_->is().compare("REAL")==0||tts_->is().compare("ENTERO")==0)){
							
					}else{
						stringstream out;
							out<<"Parametros son de difernete tipo: ";
							out<<this->expr.at(i)->is()<<endl;
							throw exception(out.str().c_str());
						}

				}else{
					if(pro->getParams()->getTable().at(i)->getVar()){
							if(this->getExpr().at(i)->is().compare("Literal_Identificador")!=0){
								stringstream out;
								out<<"Se Esperaba un literal indenditficador dentro del parametro";
							throw exception(out.str().c_str());
							}

						}

					}
				}
				

			}else{
				stringstream out;
				out<<"Cantidad de Parametros no coinciden"<<endl;
				throw exception(out.str().c_str());
			}
			}else{
				funcion *pro = (funcion*)its->getTipo();
			if(pro->getParams()->getTable().size()==this->expr.size()){
				for(int i = 0; i<this->expr.size();i++){
					tipo_ts *tts_ = this->expr.at(i)->validarSemantica(tabla_de_tipo,tabla_de_varaible);

					if(pro->getParams()->getTable().at(i)->getTipo()->is().compare(tts_->is())!=0){
						if((pro->getParams()->getTable().at(i)->getTipo()->is().compare("REAL")==0 || pro->getParams()->getTable().at(i)->getTipo()->is().compare("ENTERO")==0)&&(tts_->is().compare("REAL")==0||tts_->is().compare("ENTERO")==0)){
							
					}else{
						stringstream out;
							out<<"Parametros son de difernete tipo: ";
							out<<this->expr.at(i)->is()<<endl;
							throw exception(out.str().c_str());
						}
					}else{
						if(pro->getParams()->getTable().at(i)->getVar()){
							if(this->getExpr().at(i)->is().compare("Literal_Identificador")!=0){
								stringstream out;
								out<<"Se Esperaba un literal indenditficador dentro del parametro";
							throw exception(out.str().c_str());
							}

						}
					}

				}
				

			}else{
				stringstream out;
				out<<"Cantidad de Parametros no coinciden"<<endl;
				throw exception(out.str().c_str());
			}
			}
			

		}else{
			stringstream out;
			out<<"Se esperaba un procedimiento o Funcion"<<endl;
			throw exception(out.str().c_str());
		}

	}else{
		stringstream out;
		out<<"Procedimiento o Funcion No Existe"<<this->getLexema()<<endl;
		throw exception(out.str().c_str());
	}
	if(this->getNext()!=0){
		this->getNext()->SetReturn(this->GetReturn());
		this->getNext()->validarSemantica(tabla_de_tipo,tabla_de_varaible);
	}
	return 0;
	}


private:
	vector<Expr*> expr;
	string lexema;

};

